package edu.office.applicationRepository;

import edu.office.entities.*;
import edu.office.tools.PersonalSessionSetup;
import edu.office.tools.PublicFields;
import edu.office.tools.StaticFields;
import edu.office.tools.Tool;
import edu.office.tools.ga.GA4Testpaper;
import edu.office.viewRepository.StudentScore;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.servlet.http.HttpServletRequest;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Named("studenttestpaperRepositoryA")
@ApplicationScoped
public class StudenttestpaperRepository extends ApplicationCommonRepository<Studenttestpaper> {

    public final static String practiceString = "Practice", examiniationString = "Examination";
    @Inject
    SubjectRepository applicationSubjectRepository;
    @Inject
     TestpaperRepository applicationTestpaperRepository;
    @Inject
    KnowledgeRepository applicationKnowledgeController;
    @Inject
    LeadpointRepository applicationLeadpointController;
    @Inject
    QuestionRepository applicationQuestionController;
    @Inject
    StudenttestpaperRepository applicationStudenttestpaperController;
    @Inject
    TestpaperRepository applicationTestpaperController;
    @Inject
    StudentRepository applicationStudent;
    @Inject
    SubjectRepository applicationSubject;
    @Inject
    PublicFields applicationPublicFields;
    @Inject
    PersonalSessionSetup personalSessionSetup;
    HashMap<Question, String> studentanswerHashMap;//试题id/学生答案
    List<Studenttestpaper> studenttestpaperList;

//==================获取学生的答案========结束=================

    public String[] getSplitStrings(String answerString) {//For the multi-Selection
        return answerString.split(",");
    }

    public String getPracticeString() {
        return practiceString;
    }

    public String getExaminiationString() {
        return examiniationString;
    }

    public List<Studenttestpaper> getStudenttestpapers(Student student, Subject subject, boolean isTestpaper) {
        List<Studenttestpaper> studentTespapersList = new LinkedList<>();
        studentTespapersList.addAll(getStudenttestpapers(student, subject, false, isTestpaper));
        studentTespapersList.addAll(getStudenttestpapers(student, subject, true, isTestpaper));
        return studentTespapersList;
    }

    public List<Studenttestpaper> getStudenttestpapers(Student student, Subject subject, boolean isfinished, boolean isTestpaper) {
        List<Testpaper> candidateTestpapers = applicationTestpaperRepository.getTestpaper4SchoolSubject(student.getSCHOOL_ID(), subject.getID(), isTestpaper);
        List<Studenttestpaper> studentTespapersList = new LinkedList<>();
        String sqlString;
        for (Testpaper testpaper : candidateTestpapers) {
            sqlString = "select * from studenttestpaper where student_id=" + student.getId() + " and testpaperid=" + testpaper.getID() + " and finished=" + isfinished;
            studentTespapersList.addAll(find(sqlString).list());
        }
        setDataChanged(false);
        return studentTespapersList;
    }

    public List<Studenttestpaper> getStudenttestpaper4Leadpoint(Leadpoint leadpoint) {
        return find("LEADPOINT_ID", leadpoint).list();
    }

    public List<Studenttestpaper> getStudenttestpaper4Testpaper(Integer testpaperId) {
        return find("TESTPAPERID", testpaperId).list();
    }

    public List<Studenttestpaper> getStudenttestpaper4Student(Integer studentId) {
        return find("STUDENT_ID", studentId).list();
    }

    public HashMap<String, Integer> getWrongAnswerHashMap(int id) {
        String idString = String.valueOf(id);
        HashMap<String, Integer> result = new HashMap<>();
        List<Studenttestpaper> studenttestpapersList = find("select * from studenttestpaper where locate('," + id + "', FIRST_WRONGQUESTIONIDS)>0 or locate('" + id + ",', FIRST_WRONGQUESTIONIDS)>0").list();
        for (Studenttestpaper studenttestpaper : studenttestpapersList) {
            String[] firstWrongQuestionIds = studenttestpaper.getFIRST_WRONGQUESTIONIDS().split(",");
            String[] studentWrongAnswers = studenttestpaper.getSTUDENT_ANSWER().split(",");
            for (String wrongquestionId : firstWrongQuestionIds) {
                if (wrongquestionId.equals(idString)) {
                    // result.get(id)
                }
            }
        }
        return result;
    }

    public String getName(Studenttestpaper studTstPap) {
        StringBuilder sb = new StringBuilder();
        String[] subjectIds = applicationTestpaperRepository.find("ID", studTstPap.getTESTPAPERID()).firstResult().getSUBJECTIDS().split(",");
        for (String subjectId : subjectIds) {
            sb.append(applicationSubjectRepository.find("ID", Integer.parseInt(subjectId)).firstResult().getNAME()).append(",");
        }
        LocalDateTime endTime = applicationTestpaperRepository.find("ID", studTstPap.getTESTPAPERID()).firstResult().getENDTIME();
        sb.append(endTime.getYear()).append("/").append(endTime.getMonth()).append("/").append(endTime.getDayOfMonth());
        return sb.toString();
    }


    //存储平时练习的testpaper


    //=======================判卷================================
    float score = 0, sum = 0;
    //   boolean newScoreNeeded = false;//如果是仅仅刷新页面，而没有重新做题，则不再重新计算分数和保存数据到数据库

    // final List<Question> temWrongQuestionList = new LinkedList<>();

    //用来记录当前考试过程中的错题，在批改试卷过程中加入
    //当开始新考试时，该列表要被清空
//    public List<Question> getTemWrongQuestionList() {
//        return temWrongQuestionList;
//    }
//
//    public void temWrongQuestionListClear() {
//        temWrongQuestionList.clear();
//    }
    //For export student testpaper
    Character start = 'A';
    //==================获取学生的答案========开始=================
    String[] stduentAnswers = new String[1];
    //                    数据库中判断：
//                        1
//                        2 填空
//                        3 单选
//                        4 判断
//                        5 客观编程
//                        6 多选
//                        7 主观编程
    Studenttestpaper temTestpaper = new Studenttestpaper();
    String[] studentAnswerStrings;//According to testpaper, give the answer string, which is useful to show students answer on the pages

    public String correctTestpaper(Studenttestpaper studenttestpaper, HashMap<Question, String> studentanswerHashMap) {//判卷
        // if (isNewScoreNeeded()&& null==result) {
        score = 0;//学生得分
        sum = 0;//整张试卷的分数
        Question tem;
        Set<Question> rightquestionList = new HashSet<>(), wrongquestionList = new HashSet<>();
        studentanswerHashMap.forEach((question, studentAnswer) -> {
            sum += question.getSCORE();
            switch (question.getTYPE()) {
                case StaticFields.JUDGMENT:
                case StaticFields.SINGLESELECTION:
                case StaticFields.MULTISELECTION:
                    score += getScore(question, studentAnswer, rightquestionList, wrongquestionList);
                    break;
                case StaticFields.SINGLEFILL:
                    score += getSingleFillScore(question, studentAnswer, rightquestionList, wrongquestionList);
                    break;
//                case StaticFields.MULTIFILL:
//                    score += getMultiFillScore(question, studentAnswer);
//                    break;
                case StaticFields.OBJECTIVEPROGRMA://能够自动判卷
                    score += getSingleFillScore(question, studentAnswer, rightquestionList, wrongquestionList);
                    break;
                case StaticFields.SUBJECTIVEPROGRAM://不能自动判卷
                    score += getSingleFillScore(question, studentAnswer, rightquestionList, wrongquestionList);
                    break;
                case StaticFields.SIMPLEANSWER://需要加入语义距离计算
                    //本来应该调用方法getSimpleAnswerScore(question, studentAnswer);，但由于成本太高（需要大数据平台，需要深度学习），目前尚未实现，所以先不实现
                    score += getSingleFillScore(question, studentAnswer, rightquestionList, wrongquestionList);
                    break;
            }
        });
        //保存分数，错题集
        studenttestpaper.setTESTSCORE((double) Math.round(score / sum * 100));
        if (!wrongquestionList.isEmpty()) {
            String wrongQuestionString = "";
            wrongQuestionString = wrongquestionList.stream().map((question) -> "," + question.getID()).reduce(wrongQuestionString, String::concat);
            wrongQuestionString = wrongQuestionString.substring(1);
            if (studenttestpaper.getFIRST_WRONGQUESTIONIDS().trim().length() <= 0) {//是第一次做这套试卷
                studenttestpaper.setFIRST_WRONGQUESTIONIDS(wrongQuestionString);
            } else {//不是第一次做这个试卷了
            }
        }
        //根据错题集和对题集更新知识前点前
        String subjectString = applicationTestpaperController.find("ID", studenttestpaper.getTESTPAPERID()).firstResult().getSUBJECTIDS();
       applicationLeadpointController.updateLeadPoint(rightquestionList, wrongquestionList,
                applicationSubject.findById( Integer.valueOf(subjectString.split(",")[0])),
                applicationStudent.find("ID", studenttestpaper.getSTUDENT_ID()).firstResult()
        );
        //  result = null;
        // }
        return score + "/" + sum;
    }

    public void generateAnswerCard(Studenttestpaper studenttestpaper) {
        //Input:一张试卷，试卷包含题目
        //output:一张答题卡
        //主体：题目--ids-->题目类型--->
        //1.分组
        //2. 类型：判断题，调用YN图；单选题，调用ABCD；多选题：填空题，留空长度估计；
        //假设：题目是按照类型分组了；-->组间分隔符
        String questionIds = studenttestpaper.getQUESTION_IDS();
        String questionIdArray[] = questionIds.split(",");
        int[] typeCount = new int[7];//题目类型计数器
        for (int i = 0; i < questionIdArray.length; i++) {
            Question question = applicationQuestionController.find("ID", Integer.parseInt(questionIdArray[i])).firstResult();
            typeCount[question.getTYPE() - 1]++;
        }
        //知道各种类型题目的数量，下面制作答题卡
        for (int i = 0; i < typeCount.length; i++) {
            if (i == 0) {//简答
                for (int j = 0; j < typeCount[i]; j++) {

                }
            }
        }
    }

    int getSingleFillScore(Question question, String studentAnswer, Set<Question> rightquestionList, Set<Question> wrongquestionList) {
        int temscore = 0;
        //Match with multi-option and remove the meaningless character
        String[] questionAnswers = question.getANSWER().split(StaticFields.SECONDDELIMITED);//候选正确的选项由SECONDDELIMITED决定
        boolean correct = false;
        studentAnswer = Tool.HtmlTagRemover(studentAnswer);//删除HTML标签内容
        for (int i = 0; i < questionAnswers.length; i++) {//候选答案个数
            if (studentAnswer.replaceAll(" ", "").equals(questionAnswers[i].replaceAll(" ", ""))) {
                temscore = question.getSCORE();
                rightquestionList.add(question);
                correct = true;
                break;
            }
        }
        if (!correct) {
            wrongquestionList.add(question);
            //temWrongQuestionList.add(question);
            temscore = 0;
        }
        return temscore;
    }

    public void correctAllTestPapers(String studentIds) {
        HashMap<Question, String> studentAnswer4Question = new HashMap<>();
        List<Question> questions = new LinkedList<>();
        String[] studentAnswer;
        int i;
        List<Studenttestpaper> testpapers = applicationStudenttestpaperController.list("select * from studenttestpaper where testscore=0 and length(student_Answer)>0 and student_id in (" + studentIds + ")");
        HashMap<Question, String> studentanswerHashMap = new HashMap<>();
        for (Studenttestpaper studenttestpaper : testpapers) {
            i = 0;
            studentAnswer = studenttestpaper.getSTUDENT_ANSWER().split(StaticFields.FIRSTDELIMITED);
            questions.clear();
            questions =applicationQuestionController.getTestQuestion(studenttestpaper);
            for (Question question : questions) {
                studentanswerHashMap.put(question, studentAnswer[i++]);
            }
            ;
            correctTestpaper(studenttestpaper, studentanswerHashMap);
        }
    }

    int getScore(Question question, String studentAnswer, Set<Question> rightquestionList, Set<Question> wrongquestionList) {
        int temscore = 0;
        try {
            String questionString = question.getANSWER().replaceAll(" ", "");
            String studentTemAnswer = studentAnswer.replaceAll(" ", "");
            if (questionString.equals(studentTemAnswer)) {
                temscore = question.getSCORE();
                rightquestionList.add(question);
            } else {
                wrongquestionList.add(question);
                //temWrongQuestionList.add(question);
            }
        } catch (Exception e) {
            System.out.println("studetntestpapercontroller--getScore");
        }
        return temscore;
    }

    //根据班级和学科与教师从数据库中获得相应的试卷
    //Calculte the score for the school
    public String getScore(School resultSchool, Subject subject, HashMap<Student, List<Studenttestpaper>> practiceTestpaper, HashMap<Student, List<Studenttestpaper>> examinationTestpaper) {
        //type==1 means to get the score
        //type==2 means to export the practice and the testpapers
        //Prepare the datatable
        List<StudentScore> examinationList = new LinkedList<>();
        List<StudentScore> practiceList = new LinkedList<>();
        //Prepare studentIds
        String studentIdString = "";
        List<Student> studentList= applicationStudent.list("SCHOOL_ID",resultSchool);
        studentIdString = studentList.stream().map(student -> "," + student.getId()).reduce(studentIdString, String::concat);
        studentIdString = studentIdString.substring(1);
        //search the testpaper
        List<Testpaper> testpapers = applicationTestpaperController.list("select * from testpaper "
                + " where locate('" + subject.getID() + "',subjectIds)>0"
                //+ " and createteacherId=" + teacherAdminController.getLoginTeacherAdmin().getId()
                + " and schoolid=" + resultSchool.getID()
        );
        //过滤课程======================begin===================
        testpapers = testpapers.stream().filter((Testpaper t) -> {//下面是实现Predicate<T>类中的boolean test方法，
            String[] subjects = t.getSUBJECTIDS().split(",");
            for (String subject1 : subjects) {
                if (subject1.equals(String.valueOf(subject.getID()))) {
                    return true;
                }
            }
            return false;
        }).collect(Collectors.toList());
        //过滤课程======================end===================
        String testpaperIdString = "";
        testpaperIdString = testpapers.stream().map(testpaper -> "," + testpaper.getID()).reduce(testpaperIdString, String::concat);
        List<Studenttestpaper> testpapersList = new LinkedList<>();
        if (testpaperIdString.trim().length() > 0) {
            testpaperIdString = testpaperIdString.substring(1);
            testpapersList = applicationStudenttestpaperController.list("select * from studenttestpaper"
                    + "  where testpaperid in (" + testpaperIdString + ") "
                    + " and student_id in (" + studentIdString + ")");
        }
        //put the testpaperlist into two HashMap which represents the practice and examination respectively
        for (Studenttestpaper studenttestpaper : testpapersList) {
            Studenttestpaper studenttestpaper1 = (Studenttestpaper) studenttestpaper;
            if (applicationTestpaperController.find("ID", studenttestpaper1.getTESTPAPERID()).firstResult().getISTEST()) {
                if (null == examinationTestpaper.get(studenttestpaper1.getSTUDENT_ID())) {
                    examinationTestpaper.put(applicationStudent.find("ID", studenttestpaper1.getSTUDENT_ID()).firstResult(), new LinkedList<>());
                    examinationTestpaper.get(studenttestpaper1.getSTUDENT_ID()).add(studenttestpaper1);
                } else {//only get the last examination, therefore clear those records that are not the last one
                    if (examinationTestpaper.get(studenttestpaper1.getSTUDENT_ID()).get(0).getID() > studenttestpaper.getID()) {
                        //the stored is the last one, therefore,just keep it

                    } else {//the new comming is the last one, first remove the existed and then add it to the list
                        examinationTestpaper.get(studenttestpaper1.getSTUDENT_ID()).clear();
                        examinationTestpaper.get(studenttestpaper1.getSTUDENT_ID()).add(studenttestpaper1);
                    }
                }

            } else {
                if (null == practiceTestpaper.get(studenttestpaper1.getSTUDENT_ID())) {
                    practiceTestpaper.put(applicationStudent.find("ID", studenttestpaper1.getSTUDENT_ID()).firstResult(), new LinkedList<>());
                }
                practiceTestpaper.get(studenttestpaper1.getSTUDENT_ID()).add(studenttestpaper1);
            }
        }
        //prepare for the data for the datatable
        prepareDataTable(practiceTestpaper, practiceList);
        prepareDataTable(examinationTestpaper, examinationList);
        return null;
    }

    void prepareDataTable(HashMap<Student, List<Studenttestpaper>> testMap, List<StudentScore> studentScoresList) {
        studentScoresList.clear();
        testMap.forEach((Student student, List<Studenttestpaper> testpaperList1) -> {
            float sum1 = 0;
            List<Double> scoreList = new LinkedList<>();
            for (Studenttestpaper studenttestpaper : testpaperList1) {
                sum1 += studenttestpaper.getTESTSCORE();
                scoreList.add(studenttestpaper.getTESTSCORE());
            }
            StudentScore temStudentScore = new StudentScore();
            temStudentScore.setStudent(student);
            temStudentScore.setScore(scoreList);
            temStudentScore.setAverageScore(sum1 / testpaperList1.size());
            studentScoresList.add(temStudentScore);
        });
    }

    //=======================得到学生的当前准备做的试卷========
//=====注意这个试卷是只为当前的学生，根据其知识点前沿生成的测试试卷===================
    //isTest dedicate whether the tesp paper is for examination or just practice, true for examination and falsue for practice
    public HashSet<Studenttestpaper> getStudentTestPaper(boolean isTest, Subject subject, Student student) {
        return new HashSet<>(applicationStudenttestpaperController.getStudenttestpapers(student, subject, false, isTest));
    }

    public Studenttestpaper getTestpaper4leadPoint(Student student, Subject subject) {
        Studenttestpaper result = new Studenttestpaper();
        result.setSTUDENT_ID(student.getId());
        //学生自己要求生成的，用于学生自己巩固学习的
        //下面是根据知识点前沿生成测试题，以及对知识点前沿进行更新
        Leadpoint leadpoint = applicationLeadpointController.getLeadpointFront4Subject4Student(subject, student);
        if (null != leadpoint) {
            List<Studenttestpaper> studenttestpapersList = new LinkedList<>();
            studenttestpapersList.addAll(applicationStudenttestpaperController.list("select * from STUDENTTESTPAPER where "
                    + "leadpoint_id= " + leadpoint.getID() + " and finished= false"));
            if (!studenttestpapersList.isEmpty()) {//取尚未完成的试卷
                result = studenttestpapersList.get(0);
            } else {//已经全部提交答案或者还没有任何已经生成的试卷，因此，需要生成一份新的试卷
                result = generateTestpaper4Leadpoint(leadpoint, student);
            }
        }
        return result;
    }

    /*
     *Only for self practice
     */
    Studenttestpaper generateTestpaper4Leadpoint(Leadpoint leadpoint, Student student) {
        Studenttestpaper result = new Studenttestpaper();
        /*对KNF中的每个知识点进行如下处理：
         {
            1. 当前的知识点是否有习题？
          1.1 有，转2
          1.2 无，转3
        2. 选择不在对题集中的题目，生成候选题目；
          3. 则继续循环
            }
            4. 获得的题目集合是否为空？
          4.1 是，则
               4.1.1 知识点前沿前移；
                  4.1.1.1 是否已经到达end结点？
                   4.1.1.1.1 是，结束，并通知用户，练习结束；
                       4.1.1.1.2 否，基于该知识点继续调用本方法
         4.2 否，则返回题目集合；
         */

        //1. 当前的知识点是否有习题？
        List<Knowledge> knowledgesList = applicationKnowledgeController.getKnowledgesList4LeadingPoint(leadpoint);
        List<Question> questionsList = new LinkedList<>();
        for (Knowledge knowledge : knowledgesList) {//对KNF中的每个知识点进行如下处理：
            if (applicationQuestionController.list("KNOWLEDGE_ID", knowledge.getID()).isEmpty()) { //1. 当前的知识点是否有习题？
                continue;// 3. 有无后继？
            } else {//2. 选择不在对题集中的题目，生成候选题目；
                Set<Question> temQuestionsSet = new HashSet<>();
                temQuestionsSet.addAll(applicationQuestionController.list("KNOWLEDGE_ID", knowledge.getID()));//不破坏原集合
                //对的题目的集合
                //temQuestionsSet.removeAll(questionController.getSubjectCorrectQuestion().get(knowledge.getSubjectId()));
                questionsList.addAll(temQuestionsSet);
            }
        }

        if (questionsList.isEmpty()) {// 4. 获得的题目集合是否为空？ 4.1 是，则
            //4.1.1 知识点前沿前移；
            Leadpoint nextLeadpoint = applicationLeadpointController.getNextLeadpoint(leadpoint);
            //4.1.1.1 是否已经到达end结点？
            if (applicationLeadpointController.isEnd(nextLeadpoint))//4.1.1.1.1 是，结束，并通知用户，练习结束；
            {
                System.out.println("KnowledgeOver");
            } else {   //4.1.1.1.2 否，基于该知识点继续调用本方法
//                applicationLeadpointController.create(nextLeadpoint);
//                leadpoint=nextLeadpoint;
//                generateTestpaper4Leadpoint(nextLeadpoint, student);
                System.out.println("Noquestions");
            }
        } else {//4.2 否，则返回题目集合；
            result = new Studenttestpaper();
            String questionIds = "";
            questionIds = questionsList.stream().map((question) -> "," + question.getID()).reduce(questionIds, String::concat);
            questionIds = questionIds.substring(1);
            //看看是否有相同的试卷了
            Studenttestpaper sameTestpapers = null;
            boolean existed = false;
            List<Studenttestpaper> studenttestpaperList1=applicationStudenttestpaperController.list("STUDENT_ID",student.getId());
            for (Studenttestpaper tp : studenttestpaperList1) {
                if (tp.getQUESTION_IDS().equals(questionIds)) {
                    sameTestpapers = tp;
                    existed = true;
                    break;
                }
            }
            if (!existed) {
                result.setTESTPAPERID(null);
                result.setQUESTION_IDS(questionIds);
                result.setSTUDENT_ID(student.getId());
                result.setLEADPOINT_ID(leadpoint.getID());
                result.setANSWERED_INTERVAL(0);
                result.setFINISHED(false);
                result.setTESTSCORE(0d);
                result.setSTUDENT_ANSWER("");
                result.setFIRST_WRONGQUESTIONIDS("");
                applicationStudenttestpaperController.create(result);
            } else {//存在相同的试卷
                result.setANSWERED_INTERVAL(0);
                result.setFINISHED(false);
                System.out.println("Thisis Old Testpaper");
            }
        }
        return result;
    }

    public Studenttestpaper generateTestpaper4Question(List<Question> questionList, Student student, Testpaper testpaper) {
        //考虑做题时所需要的时间与安排的时间之间的关系，是否也作为一个约束条件 ？
        Studenttestpaper result = new Studenttestpaper();
        String questionIds = "";
        questionIds = questionList.stream().map((question) -> "," + question.getID()).reduce(questionIds, String::concat);
        if (questionIds.length() > 1) {
            questionIds = questionIds.substring(1);
            dealwithDuplicateTestpaper(questionIds, student, testpaper);
        }
        result.setQUESTION_IDS(questionIds);
        result.setSTUDENT_ID(student.getId());
        result.setTESTPAPERID(testpaper.getID());
        return result;
    }

    Studenttestpaper dealwithDuplicateTestpaper(String questionIds, Student student, Testpaper testpaper) {
        Studenttestpaper result = new Studenttestpaper();
        //看看是否有相同的试卷了
        Studenttestpaper sameTestpapers = null;
        boolean existed = false;

        List<Studenttestpaper> studenttestpaperList1=applicationStudenttestpaperController.list("STUDENT_ID",student.getId());
        for (Studenttestpaper tp : studenttestpaperList1) {
            if (tp.getQUESTION_IDS().equals(questionIds)) {
                sameTestpapers = tp;
                existed = true;
                break;
            }
        }
        if (!existed) {
            result.setTESTPAPERID(testpaper.getID());
            result.setQUESTION_IDS(questionIds);
            result.setSTUDENT_ID(student.getId());
            result.setLEADPOINT_ID(null);
            result.setANSWERED_INTERVAL(0);
            result.setFINISHED(false);
            result.setTESTSCORE(0d);
            result.setSTUDENT_ANSWER("");
            result.setFIRST_WRONGQUESTIONIDS("");
            applicationStudenttestpaperController.create(result);
        } else {//存在相同的试卷
            result.setANSWERED_INTERVAL(0);
            result.setFINISHED(false);
            System.out.println("Thisis Old Testpaper");
        }
        return result;
    }

    /**
     * For testpaper or homework, the leadpoint will not be provided, therefore,
     * leadpoint is null here
     *
     * @param knowledgesList
     * @param student
     * @param testpaper
     */
    public void generateTestpaper4KnowledgeList(Set<Knowledge> knowledgesList, Student student, Testpaper testpaper) {
        try {
            //考虑做题时所需要的时间与安排的时间之间的关系，是否也作为一个约束条件 ？
            String questionIds = "";
            GA4Testpaper ga = new GA4Testpaper();
            Set<Question> questionsList = new HashSet<>();
            Set<Question> allKnowlegeQuestion = new HashSet<>();
            for (Knowledge knowledge : knowledgesList) {
                allKnowlegeQuestion.addAll(applicationQuestionController.getQuestion4Knowledge(knowledge));
            }
            if (null != testpaper) {
                questionsList = ga.getCandidateQuestions(knowledgesList, testpaper.getSCORE(), testpaper.getDEGREE(),
                        allKnowlegeQuestion);
                //是考试，看分数是否满足指定条件，如果不满足，则进行调整。不满足的情况包括2个方面：分数不够，分数过多。
                //检查分数情况
                int sumscore = 0;
                for (Question question : questionsList) {
                    sumscore += question.getSCORE();
                }
                sumscore = sumscore - testpaper.getSCORE();
                //针对分数不够的情况，加入一道分值最接近缺口的题目
                if (sumscore != 0) {
                    if (sumscore < 0) {
                        //拿到所有可以使用的题目
                        Set<Question> allQuestions = new HashSet<>();
                        for (Knowledge knowledge : knowledgesList) {
                            allQuestions.addAll(applicationQuestionController.list("KNOWLEDGE_ID", knowledge.getID()));
                        }
                        allQuestions.removeAll(questionsList);
                        //限定只加入一个题目，因此找一个与sumscore最接近的题目即可
                        Question temQuestion = null;//保存临时Question
                        int minDifference = 20;//保存临时最小差值
                        int temDiff = 0;//保存临时的差值，其作用范围在下面的循环中，但是为了避免反复定义变量，从而产生内存碎片，写在循环外边了
                        for (Question question : allQuestions) {
                            temDiff = Math.abs(question.getSCORE() - sumscore);//用临时变量，避免反复计算，用内存空间换CPU计算时间
                            if (temDiff < minDifference) {//找到了一个更适合的
                                temQuestion = question;
                                minDifference = temDiff;
                                if (temDiff == 0) {
                                    break;//找到了一个正好的，就不再处理其他的
                                }
                            }
                        }
                        questionsList.add(temQuestion);
                    } else if (sumscore > 0) {
                        //针对分数过多的情况，从中去掉最低的分数
                        Question temQuestion = null;//保存临时Question
                        int minDifference = 20;//保存临时最小差值
                        int temDiff = 0;//保存临时的差值，其作用范围在下面的循环中，但是为了避免反复定义变量，从而产生内存碎片，写在循环外边了
                        for (Question question : questionsList) {
                            temDiff = Math.abs(question.getSCORE() - sumscore);
                            if (temDiff < minDifference) {//找到了一个更适合的
                                temQuestion = question;
                                minDifference = temDiff;
                                if (temDiff == 0) {
                                    break;//找到了一个正好的，就不再处理其他的
                                }
                            }
                        }
                        questionsList.remove(temQuestion);
                    }
                }
            } else {//It is from self practice
                for (Knowledge knowledge : knowledgesList) {
                    questionsList.addAll(applicationQuestionController.list("KNOWLEDGE_ID", knowledge.getID()));
                }
            }
            HashSet<Integer> idSet = new HashSet<>();
            for (Question question : questionsList) {
                idSet.add(question.getID());
            }
            for (Integer qId : idSet) {
                questionIds += "," + qId;
            }
            if (questionIds.length() > 1) {
                questionIds = questionIds.substring(1);
                dealwithDuplicateTestpaper(questionIds, student, testpaper);
            }
        } catch (CloneNotSupportedException ex) {
            System.out.println("studetntestpapercontroller--Clone");
        }
    }


    public String[] writeStudentTestpapers2File(School school, Subject subject, TeacherAdmin teacherAdmin, HttpServletRequest origRequest) {
        File[] files = {
                new File(personalSessionSetup.getFileName(personalSessionSetup.getFilePath()
                                + "/" + applicationStudenttestpaperController.getExaminiationString(),
                        "TP" + teacherAdmin.getID(), "html")),
                new File(personalSessionSetup.getFileName(personalSessionSetup.getFilePath()
                                + "/" + applicationStudenttestpaperController.getPracticeString(),
                        "TP" + teacherAdmin.getID(), "html"))};
        try {
            FileWriter[] fw = {new FileWriter(files[0]), new FileWriter(files[1])};
            StringBuilder[] stpSB = {new StringBuilder(), new StringBuilder()};
            String head = "<html> <head><title></title><meta charset=\"UTF-8\">"
                    + "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
                    + "</head><body>";
            for (FileWriter f : fw) {
                f.append(head);
                f.flush();
            }
            int radioGroupNumber = 0;//For radio group
            HashMap<String, HashMap<Student, List<Studenttestpaper>>> shl = getTestpaperMap(school, subject);
            List<HashMap<Student, List<Studenttestpaper>>> exsstp = new LinkedList<>();
            exsstp.add(shl.get(applicationStudenttestpaperController.getExaminiationString()));
            exsstp.add(shl.get(applicationStudenttestpaperController.getPracticeString()));
            for (int i = 0; i < 2; i++) {
                for (Map.Entry<Student, List<Studenttestpaper>> item : exsstp.get(i).entrySet()) {
                    fw[i].append(stpSB[i].toString());
                    fw[i].flush();
                    stpSB[i].replace(0, stpSB[i].length(), "");
                    stpSB[i].append(item.getKey().getSCHOOL_ID()).append(":");
                    stpSB[i].append(item.getKey().getNAME()).append("<br>");//Student schoolID
                    stpSB[i].append(item.getKey().getSecondname()).append(" ").append(item.getKey().getFirstname()).append("<br>");
                    for (Studenttestpaper temTestpaper : item.getValue()) {
                        stpSB[i].append("=============================================");
                        stpSB[i].append(temTestpaper.getTESTSCORE()).append("<br>");
                        int questionNumberLabel = 0;
                        String[] studentAnswerStrings = getStudentAnswerStrings(temTestpaper);

                        for (Question question : applicationQuestionController.getTestQuestion(temTestpaper)) {
                            stpSB[i].append("-------------------------<br>");
                            stpSB[i].append(questionNumberLabel + 1).append("<br>");
                            stpSB[i].append(question.getVALUEINFO()).append("<br>");
                            stpSB[i].append("Your Answer:");
                            if (questionNumberLabel >= studentAnswerStrings.length) {
                                stpSB[i].append("No Finished<br>");
                                break;//Students didn't finished this exam
                            } else {
                                stpSB[i].append(studentAnswerStrings[questionNumberLabel])
                                        .append("<br>");
                            }
                            if (applicationQuestionController.isSingleFill(question.getTYPE())) {
                                stpSB[i].append(studentAnswerStrings[questionNumberLabel]).append("<br>");
                            }
                            if (applicationQuestionController.isJudgment(question.getTYPE())) {
                                stpSB[i].append("<input type=\"radio\" name =\"StudentAnswer")
                                        .append(radioGroupNumber).append("\"")
                                        //.append(" value=\" \"")
                                        .append(studentAnswerStrings[questionNumberLabel]
                                                .trim().equals("T") ? " checked" : "")
                                        .append(">")
                                        .append("True")
                                        .append("</input>")
                                        .append("<input type=\"radio\" name =\"StudentAnswer")
                                        .append(radioGroupNumber).append("\"")
                                        //.append(" value=\"\"")
                                        .append(studentAnswerStrings[questionNumberLabel]
                                                .trim().equals("F") ? " checked" : "")
                                        .append(">")
                                        .append("False")
                                        .append("</input>");
                                radioGroupNumber++;
                            }

                            if (applicationQuestionController.isSimpleAnswer(question.getTYPE())) {
                                stpSB[i].append(studentAnswerStrings[questionNumberLabel]).append("<br>");
                            }
                            if (applicationQuestionController.isSingleSelection(question.getTYPE())) {
                                int j = 0;
                                for (String optionDescription : applicationQuestionController.getSelectionOptionStrings(question)) {
                                    stpSB[i].append("<input type=\"radio\" name =\"StudentAnswer")
                                            .append(radioGroupNumber).append("\"")
                                            // .append(" value=\" ")
                                            .append(studentAnswerStrings[questionNumberLabel]
                                                    .trim().equals(String.valueOf(j + 1)) ? " checked" : " ")
                                            .append(">")
                                            .append(Character.valueOf((char) (start + j++)).toString())
                                            .append(".")
                                            .append(optionDescription)
                                            .append("<br>");
                                }
                                radioGroupNumber++;
                            }

                            if (applicationQuestionController.isMultiSelection(question.getTYPE())) {
                                stpSB[i].append("<select multiple=\"multiple\">");
                                int j = 1;
                                for (String optionDescription : applicationQuestionController.getSelectionOptionStrings4Multi(question)) {
                                    stpSB[i].append("<option");
                                    stpSB[i].append(studentAnswerStrings[questionNumberLabel].contains(String.valueOf(j)) ? " selected=\"selected\"" : "");
                                    stpSB[i].append(">");
                                    stpSB[i].append(Character.valueOf((char) (start + j - 1)).toString())
                                            .append(".")
                                            .append(optionDescription)
                                            .append("</option>");
                                    j++;
                                }

                                stpSB[i].append("</select>");
                            }
                            stpSB[i].append("<br>").append("Reference Answer")
                                    .append(":").append(question.getANSWER()).append("<br>");
                            questionNumberLabel++;
                        }
                    }
                }
                fw[i].append(stpSB.toString());
                fw[i].append("</body>\n</html>");
                fw[i].flush();
                fw[i].close();
                stpSB[i].replace(0, stpSB[i].length(), "");//clear the content and free the memory
            }
        } catch (IOException ex) {
            System.out.println("studetntestpapercontroller--fwclose");
        }
        String str1=applicationPublicFields.getFileRepository(origRequest) + applicationStudenttestpaperController.getExaminiationString() + "/" + files[0].getName(),
                str2= applicationPublicFields.getFileRepository(origRequest) + applicationStudenttestpaperController.getPracticeString() + "/" + files[1].getName();
        String[] result={str1,str2};
        return result;
    }

    public HashMap<String, HashMap<Student, List<Studenttestpaper>>> getTestpaperMap(School school, Subject subject) {
        HashMap<Student, List<Studenttestpaper>> practiceTestpaper = new HashMap<>();
        HashMap<Student, List<Studenttestpaper>> examinationTestpaper = new HashMap<>();
        getScore(school, subject, practiceTestpaper, examinationTestpaper);
        HashMap<String, HashMap<Student, List<Studenttestpaper>>> result = new HashMap<>();
        result.put(applicationStudenttestpaperController.getExaminiationString(), examinationTestpaper);
        result.put(applicationStudenttestpaperController.getPracticeString(), practiceTestpaper);
        return result;
    }

    public String[] getStudentAnswerStrings(Studenttestpaper testpaper) {
        if (null != testpaper) {
            if (null == temTestpaper.getID() || !Objects.equals(temTestpaper.getID(), testpaper.getID())) {
                //如果是取同一个试卷的内容，就不必重复计算了
                temTestpaper = testpaper;
                studentAnswerStrings = testpaper.getSTUDENT_ANSWER().split(StaticFields.FIRSTDELIMITED);
            }
        }
        return studentAnswerStrings;
    }
}
